import type { Command, CommandOptions } from '@teambit/cli';
import chalk from 'chalk';
import { COMPONENT_PATTERN_HELP } from '@teambit/legacy.constants';
import type { ComponentMain } from '@teambit/component';
import type { BuilderMain } from '../builder.main.runtime';
import type { ExtractorArtifactResult, ExtractorResultGrouped } from './artifact-extractor';
import { ArtifactExtractor } from './artifact-extractor';

const INDENT_TITLE = ' '.repeat(2);
const INDENT_SUB_TITLE = ' '.repeat(4);
const INDENT_FILES = ' '.repeat(6);

export type ArtifactsOpts = {
  aspect?: string;
  task?: string;
  files?: string;
  outDir?: string;
};

export class ArtifactsCmd implements Command {
  name = 'artifacts <component-pattern>';
  description = 'view and download build artifacts';
  extendedDescription = `displays artifacts created during the build pipeline in isolated capsules during tag or snap operations.
artifacts include compiled files, test reports, package files, and other build outputs generated by various tasks.
use --out-dir to download artifacts locally for inspection or deployment purposes.`;
  arguments = [
    {
      name: 'component-pattern',
      description: COMPONENT_PATTERN_HELP,
    },
  ];
  alias = '';
  group = 'testing';
  helpUrl = 'reference/components/component-artifacts';
  options = [
    ['', 'aspect <aspect-id>', 'show/download only artifacts generated by this aspect-id'],
    ['', 'task <task-id>', 'show/download only artifacts generated by this task-id'],
    [
      '',
      'files <glob>',
      'show/download only artifacts matching the given files or the glob pattern (wrap glob patterns in quotes)',
    ],
    ['', 'out-dir <string>', 'download the files to the specified dir'],
  ] as CommandOptions;

  constructor(
    private builder: BuilderMain,
    private componentMain: ComponentMain
  ) {}

  async report([componentPattern]: [string], artifactsOpts: ArtifactsOpts): Promise<string> {
    const artifactExtractor = new ArtifactExtractor(this.componentMain, this.builder, componentPattern, artifactsOpts);
    const list = await artifactExtractor.list();
    const grouped = artifactExtractor.groupResultsByAspect(list);
    const outputArtifacts = (aspectId: string, artifactData: ExtractorArtifactResult[]) => {
      const title = chalk.green(aspectId);
      const artifactDataStr = artifactData
        .map((artifact) => {
          const subTitle = chalk.white(`${artifact.taskName} (${artifact.artifactName})`);
          const files = artifact.files.map((f) => INDENT_FILES + chalk.dim(f)).join('\n');
          return `${INDENT_SUB_TITLE}${subTitle}\n${files}`;
        })
        .join('\n');
      return `${INDENT_TITLE}${title}\n${artifactDataStr}`;
    };
    const outputResult = (result: ExtractorResultGrouped) => {
      const idStr = chalk.cyan(result.id.toString());
      const artifacts = Object.keys(result.artifacts)
        .map((aspectId) => outputArtifacts(aspectId, result.artifacts[aspectId]))
        .join('\n\n');
      return `${idStr}\n${artifacts}`;
    };
    const footer = artifactsOpts.outDir
      ? chalk.green('\n\nThe above files were saved successfully to the file system')
      : '';
    return grouped.map(outputResult).join('\n\n') + footer;
  }
}
